package org.jsola.hr.service.impl;

import org.jsola.admin.entity.HeaderFieldsTemplateDO;
import org.jsola.cache.ICache;
import org.jsola.common.DateKit8;
import org.jsola.common.PageKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.*;
import org.jsola.hr.constant.EmpSocStatus;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.RegTypeEnum;
import org.jsola.hr.constant.SocPayCostType;
import org.jsola.hr.dao.ISocPlanDispatchUserDAO;
import org.jsola.hr.dto.SocPlanDispatchDTO;
import org.jsola.hr.dto.SocPlanDispatchUserAddDTO;
import org.jsola.hr.dto.SocPlanDispatchUserUpdateDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.SocPlanDispatchUserQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.jsola.user.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 增减员计划派单人员表
 *
 * @author zhr
 */
@Service("hrSocPlanDispatchUserServiceImpl")
public class SocPlanDispatchUserServiceImpl implements ISocPlanDispatchUserService {

    @Autowired
    private ISocPlanDispatchUserDAO socPlanDispatchUserDAO;

    @Autowired
    private IEmpSocPlanService empSocPlanService;

    @Autowired
    private IEmpSocPlanItemService empSocPlanItemService;

    @Autowired
    private IEmpSocMonthService empSocMonthService;

    @Autowired
    private ISocDifferenceService socDifferenceService;

    @Autowired
    private IEmpSocInfoService empSocInfoService;

    @Autowired
    private IEmpSocItemService empSocItemService;

    @Autowired
    private IChildCompanyService childCompanyService;

    @Autowired
    private IAdminProviderService adminProviderService;

    @Autowired
    private IUserProviderService userProviderService;

    @Autowired
    private ICache cache;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public SocPlanDispatchUserVO save(SocPlanDispatchUserAddDTO socPlanDispatchUserAddDTO, TokenUser tokenUser) {
        // 转DO
        SocPlanDispatchUserDO socPlanDispatchUserDO = socPlanDispatchUserAddDTO.to(SocPlanDispatchUserDO.class);
        // 保存
        socPlanDispatchUserDO = save(socPlanDispatchUserDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return socPlanDispatchUserDO.to(SocPlanDispatchUserVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(SocPlanDispatchUserUpdateDTO socPlanDispatchUserUpdateDTO, TokenUser tokenUser) {
        //转DO
        SocPlanDispatchUserDO socPlanDispatchUserDO = socPlanDispatchUserUpdateDTO.to(SocPlanDispatchUserDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(socPlanDispatchUserDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... socPlanDispatchUserIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) socPlanDispatchUserIds);
    }


    @Override
    public SocPlanDispatchUserVO selectById(String socPlanDispatchUserId, String siteId) {
        SocPlanDispatchUserDO socPlanDispatchUserDO = selectDOById(socPlanDispatchUserId, siteId);
        if (socPlanDispatchUserDO == null) {
            return null;
        }
        return socPlanDispatchUserDO.to(SocPlanDispatchUserVO.class);
    }

    @Override
    public List<SocPlanDispatchUserListVO> select(SocPlanDispatchUserQuery socPlanDispatchUserQuery, String siteId) {
        List<SocPlanDispatchUserDO> socPlanDispatchUserDOList = selectDO(socPlanDispatchUserQuery, siteId);
        if (CollectionUtils.isEmpty(socPlanDispatchUserDOList)) {
            return socPlanDispatchUserDOList == null ? null : new ArrayList<>();
        }
        return socPlanDispatchUserDOList.stream()
                .map(socPlanDispatchUserDO -> socPlanDispatchUserDO.to(SocPlanDispatchUserListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(SocPlanDispatchUserQuery socPlanDispatchUserQuery, String siteId) {
        Example example = buildExample(socPlanDispatchUserQuery, siteId);
        return socPlanDispatchUserDAO.selectCountByExample(example);
    }

    @Override
    public Page<SocPlanDispatchUserListVO> selectPage(SocPlanDispatchUserQuery socPlanDispatchUserQuery, String siteId) {
        Example example = buildExample(socPlanDispatchUserQuery, siteId);
        Page<SocPlanDispatchUserDO> page = socPlanDispatchUserDAO.selectPageByExample(example,
                socPlanDispatchUserQuery.getPageNo(),
                socPlanDispatchUserQuery.getPageSize());

        return page.to(SocPlanDispatchUserListVO.class);
    }

    @Override
    public SocPlanDispatchUserDO selectDOById(String socPlanDispatchUserId, String siteId) {
        return listById(socPlanDispatchUserId, siteId);
    }

    @Override
    public List<SocPlanDispatchUserDO> selectDO(SocPlanDispatchUserQuery socPlanDispatchUserQuery, String siteId) {
        Example example = buildExample(socPlanDispatchUserQuery, siteId);
        return socPlanDispatchUserDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void dispatch(SocPlanDispatchDTO socPlanDispatchDTO, TokenUser tokenUser) {
        ParamException.notEmpty(socPlanDispatchDTO.getPlanIdList(), "增减员计划不能为空");
        ParamException.notEmpty(socPlanDispatchDTO.getUserIdList(), "接单人不能为空");
        List<SocPlanDispatchUserDO> takeOrderList = new ArrayList<>();
        List<SocPlanDispatchUserDO> dispatchList = new ArrayList<>();
        List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                .selectByIdList(socPlanDispatchDTO.getPlanIdList(), tokenUser.getSiteId());
        for (EmpSocPlanDO empSocPlan : empSocPlanList) {
            // 派单人员也保存下来
            SocPlanDispatchUserDO dispatch = new SocPlanDispatchUserDO();
            dispatch.setPlanId(empSocPlan.getId());
            dispatch.setUserId(tokenUser.getUserId());
            dispatch.setType(2);
            dispatch.setCompanyId(empSocPlan.getCompanyId());
            dispatch.setEmpId(empSocPlan.getEmpId());
            dispatch.preInsert(tokenUser.getUserId());
            dispatch.setSiteId(tokenUser.getSiteId());
            dispatchList.add(dispatch);
            for (String userId : socPlanDispatchDTO.getUserIdList()) {
                List<SocPlanDispatchUserDO> socPlanDispatchUser = this
                        .selectByUserIdAndPlanId(userId, empSocPlan.getId(), 1);
                if (!CollectionUtils.isEmpty(socPlanDispatchUser)) {
                    UserVO user = userProviderService.selectById(userId);
                    throw new ParamException(user.getName() + "重复派单");
                }
                // 保存接单记录
                SocPlanDispatchUserDO takeOrder = new SocPlanDispatchUserDO();
                takeOrder.setPlanId(empSocPlan.getId());
                takeOrder.setUserId(userId);
                takeOrder.setType(1);
                takeOrder.setCompanyId(empSocPlan.getCompanyId());
                takeOrder.setEmpId(empSocPlan.getEmpId());
                takeOrder.setSiteId(tokenUser.getSiteId());
                takeOrder.preInsert(tokenUser.getUserId());
                takeOrderList.add(takeOrder);
            }
        }
        if (!CollectionUtils.isEmpty(takeOrderList)) {
            bachSave(takeOrderList);
        }
        if (!CollectionUtils.isEmpty(dispatchList)) {
            bachSave(dispatchList);
        }
    }

    @Override
    public Page<EmpSocPlanListVO> taskOrderUser(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        List<EmpSocPlanListVO> empSocPlanList = socPlanDispatchUserDAO
                .taskOrderUser(query, tokenUser.getSiteId(), tokenUser.getUserId());
        Page<EmpSocPlanListVO> pageEmpSocPlan = PageKit.startPage(empSocPlanList, query.getPageNo(), query.getPageSize());
        List<EmpSocPlanListVO> resultList = pageEmpSocPlan.getEntities();
        if (!CollectionUtils.isEmpty(resultList)) {
            for (EmpSocPlanListVO empSocPlan : resultList) {
                empSocPlan.setPlanDate(empSocPlan.getYear() + "-" + empSocPlan.getMonth());
                Map<String, Object> data = new HashMap<>();
                List<EmpSocPlanItemDO> itemList = empSocPlanItemService.selectByPlanId(empSocPlan.getId(), tokenUser);
                if (!CollectionUtils.isEmpty(itemList)) {
                    empSocPlan.setItemList(itemList);
                    for (EmpSocPlanItemDO empSocPlanItem : itemList) {
                        data.put(empSocPlanItem.getItemName() + "基数", empSocPlanItem.getCardinalityDefault());
                    }
                }
                empSocPlan.setData(data);
            }
        }
        return pageEmpSocPlan;
    }

    @Override
    public List<SocPlanDispatchUserDO> selectByUserIdAndPlanId(String userId, String planId, Integer type) {
        Example example = new Example(SocPlanDispatchUserDO.class);
        example.and()
                .andEqualTo("planId", planId)
                .andEqualTo("userId", userId)
                .andEqualTo("type", type);
        return socPlanDispatchUserDAO.selectByExample(example);
    }

    @Override
    public TaskOrderUserCountVO taskOrderUserCount(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        TaskOrderUserCountVO result = new TaskOrderUserCountVO();
        List<EmpSocPlanListVO> empSocPlanList = socPlanDispatchUserDAO
                .taskOrderUser(query, tokenUser.getSiteId(), tokenUser.getUserId());
        // 待反馈人数
        long toBeFedBackCount = empSocPlanList.stream()
                .filter(plan -> ObjectUtils.isEmpty(plan.getFeedbackFlag())).count();
        long succeedFeedbackCount = empSocPlanList.stream()
                .filter(plan -> !ObjectUtils.isEmpty(plan.getFeedbackFlag())).count();
        long failFeedbackCount = empSocPlanList.stream()
                .filter(plan -> !ObjectUtils.isEmpty(plan.getFeedbackFlag()) && 2 == plan.getFeedbackFlag()).count();
        result.setAllCount(empSocPlanList.size());
        result.setToBeFedBackCount((int) toBeFedBackCount);
        result.setSucceedFeedbackCount((int) succeedFeedbackCount);
        result.setFailFeedbackCount((int) failFeedbackCount);
        return result;
    }

    @Override
    public void bachSave(List<SocPlanDispatchUserDO> saveList) {
        if (!CollectionUtils.isEmpty(saveList)) {
            socPlanDispatchUserDAO.insertListAndSetId(saveList);
        }
    }

    @Override
    public SocOverviewItemStatsListVO socOverviewItemStats(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        SocOverviewItemStatsListVO result = new SocOverviewItemStatsListVO();
        List<SocOverviewItemStatsVO> itemStatsList = new ArrayList<>();
        List<EmpSocInfoListVO> empSocInfoList = socOverviewList(query, tokenUser);
        List<String> empSocInfoIdList = empSocInfoList
                .stream().map(EmpSocInfoListVO::getId).collect(Collectors.toList());
        List<EmpSocItemDO> empSocItemList = empSocItemService
                .selectByEmpSocIdList(empSocInfoIdList, tokenUser.getSiteId());
        List<String> itemNameList = empSocItemList.stream()
                .map(EmpSocItemDO::getItemName).distinct().collect(Collectors.toList());
        Map<String, List<EmpSocItemDO>> itemMap = empSocItemList.stream()
                .collect(Collectors.groupingBy(EmpSocItemDO::getItemName));
        for (String itemName : itemNameList) {
            SocOverviewItemStatsVO socOverviewItemStats = new SocOverviewItemStatsVO();
            socOverviewItemStats.setItemName(itemName);
            List<EmpSocItemDO> itemList = itemMap.get(itemName);
            BigDecimal amount = new BigDecimal("0");
            for (EmpSocItemDO empSocItem : itemList) {
                amount = amount.add(empSocItem.getAmountCompany()).add(empSocItem.getAmountPersonal());
            }
            socOverviewItemStats.setAmount(amount);
            itemStatsList.add(socOverviewItemStats);
        }
        result.setItemStatsList(itemStatsList);
        return result;
    }

    @Override
    public SocOverviewAmountStatsVO socOverviewAmountStats(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        ParamException.notNull(query.getDate(), "时间不能为空");
        SocOverviewAmountStatsVO result = new SocOverviewAmountStatsVO();
        List<EmpSocInfoListVO> empSocInfoList = socOverviewList(query, tokenUser);
        // 需要再拿到上个月的数据作比较
        Date date = DateKit8.parseDate(query.getDate() + "-01");
        Date previousDate = DateKit8.addMonths(date, -1L);
        String previousDateStr = DateUtils.getYearMonthByDate(previousDate);
        query.setDate(previousDateStr);
        List<EmpSocInfoListVO> previousList = socOverviewList(query, tokenUser);
        BigDecimal allAmount = new BigDecimal("0");
        BigDecimal socAmount = new BigDecimal("0");
        BigDecimal pfAmount = new BigDecimal("0");
        int empCount = 0;
        // 筛选月统计数据
        List<Integer> zbStatus = Arrays
                .asList(EmpSocStatus.INCREMENT.getValue(), EmpSocStatus.NORMAL_SOC.getValue());
        for (EmpSocInfoListVO empSocInfo : empSocInfoList) {
            if (SocPayCostType.NORMAL_PAY_COST.getValue().equals(empSocInfo.getPayCostType())) {
                if (zbStatus.contains(empSocInfo.getEmpSocStatus()) || zbStatus.contains(empSocInfo.getEmpMeStatus()) ||
                        zbStatus.contains(empSocInfo.getEmpPfStatus())) {
                    empCount++;
                }
            }
            socAmount = socAmount.add(empSocInfo.getPersonalSocAmount()).add(empSocInfo.getCompanySocAmount());
            pfAmount = pfAmount.add(empSocInfo.getPersonalPfAmount()).add(empSocInfo.getCompanyPfAmount());
        }
        allAmount = socAmount.add(pfAmount);
        BigDecimal previousAllAmount = new BigDecimal("0");
        BigDecimal previousSocAmount = new BigDecimal("0");
        BigDecimal previousPfAmount = new BigDecimal("0");
        int previousEmpCount = 0;
        // 上月统计数据
        for (EmpSocInfoListVO empSocInfo : previousList) {
            if (SocPayCostType.NORMAL_PAY_COST.getValue().equals(empSocInfo.getPayCostType())) {
                if (zbStatus.contains(empSocInfo.getEmpSocStatus()) || zbStatus.contains(empSocInfo.getEmpMeStatus()) ||
                        zbStatus.contains(empSocInfo.getEmpPfStatus())) {
                    previousEmpCount++;
                }
            }
            previousSocAmount = previousSocAmount.add(empSocInfo.getPersonalSocAmount()).add(empSocInfo.getCompanySocAmount());
            previousPfAmount = previousPfAmount.add(empSocInfo.getPersonalPfAmount()).add(empSocInfo.getCompanyPfAmount());
        }
        previousAllAmount = previousSocAmount.add(previousPfAmount);
        result.setAllAmount(allAmount);
        result.setSocAmount(socAmount);
        result.setPfAmount(pfAmount);
        result.setEmpCount(empCount);
        result.setLastAllAmount(allAmount.subtract(previousAllAmount));
        result.setLastSocAmount(socAmount.subtract(previousSocAmount));
        result.setLastPfAmount(pfAmount.subtract(previousPfAmount));
        result.setLastEmpCount(empCount - previousEmpCount);
        return result;
    }

    @Override
    public Page<EmpSocInfoListVO> socOverviewListStats(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        List<EmpSocInfoListVO> empSocInfoList = socOverviewList(query, tokenUser);
        if (CollectionUtils.isEmpty(empSocInfoList)) {
            return new Page<>(query.getPageSize(), query.getPageNo());
        }
        Page<EmpSocInfoListVO> resultPage = PageKit.startPage(empSocInfoList, query.getPageNo(), query.getPageSize());
        List<EmpSocInfoListVO> resultList = resultPage.getEntities();
        // 需要赋值一些其他信息
        List<String> idList = resultList.stream().map(EmpSocInfoListVO::getId).collect(Collectors.toList());
        // 子项信息
        List<EmpSocItemVO> empSocItemList = empSocItemService.selectByEmpSocIdList(idList, tokenUser);
        Map<String, List<EmpSocItemVO>> groupItem = empSocItemList
                .stream().collect(Collectors.groupingBy(EmpSocItemVO::getEmpSocId));
        // 差额费用
        List<SocDifferenceDO> socDifferenceList = socDifferenceService
                .selectBySocInfoIdList(idList, tokenUser.getSiteId());
        Map<String, List<SocDifferenceDO>> groupDifference = socDifferenceList.stream()
                .collect(Collectors.groupingBy(SocDifferenceDO::getSocInfoId));
        for (EmpSocInfoListVO empSocInfo : resultList) {
            Map<String, Object> data = new LinkedHashMap<>();
            fillListData(empSocInfo);
            List<EmpSocItemVO> infoItemList = groupItem.get(empSocInfo.getId());
            List<SocDifferenceDO> infoDifferenceList = groupDifference.get(empSocInfo.getId());
            if (!CollectionUtils.isEmpty(infoItemList)) {
                for (EmpSocItemVO empSocItem : infoItemList) {
                    data.put(empSocItem.getItemName() + "缴纳基数", empSocItem.getCardinalityDefault().stripTrailingZeros().toPlainString());
                    data.put(empSocItem.getItemName() + "个人缴纳比例", empSocItem.getPersentPersonal().stripTrailingZeros().toPlainString() + "%");
                    data.put(empSocItem.getItemName() + "企业缴纳比例", empSocItem.getPersentCompany().stripTrailingZeros().toPlainString() + "%");
                    data.put(empSocItem.getItemName() + "个人缴纳金额", empSocItem.getAmountPersonal().stripTrailingZeros().toPlainString());
                    data.put(empSocItem.getItemName() + "企业缴纳金额", empSocItem.getAmountCompany().stripTrailingZeros().toPlainString());
                }
            }
            BigDecimal differenceAmount = new BigDecimal("0");
            if (!CollectionUtils.isEmpty(infoDifferenceList)) {
                for (SocDifferenceDO socDifference : infoDifferenceList) {
                    data.put(socDifference.getDifferenceName() + "(企业)", socDifference.getCompanyDifference());
                    data.put(socDifference.getDifferenceName() + "(个人)", socDifference.getPersonalDifference());
                    differenceAmount = differenceAmount.add(socDifference.getPersonalDifference())
                            .add(socDifference.getCompanyDifference());
                }
            }
            empSocInfo.setServiceCost(ObjectUtils.isEmpty(empSocInfo.getServiceCost()) ? new BigDecimal("0") : empSocInfo.getServiceCost());
            data.put("社保合计", empSocInfo.getCompanySocAmount().add(empSocInfo.getPersonalSocAmount())
                    .stripTrailingZeros().toPlainString());
            data.put("公积金合计", empSocInfo.getCompanyPfAmount().add(empSocInfo.getPersonalPfAmount())
                    .stripTrailingZeros().toPlainString());
            data.put("社保公积金总合计", empSocInfo.getCompanySocAmount().add(empSocInfo.getPersonalSocAmount())
                    .add(empSocInfo.getCompanyPfAmount()).add(empSocInfo.getPersonalPfAmount())
                    .stripTrailingZeros().toPlainString());
            data.put("应收总合计", empSocInfo.getCompanySocAmount().add(empSocInfo.getPersonalSocAmount())
                    .add(empSocInfo.getCompanyPfAmount()).add(empSocInfo.getPersonalPfAmount()).add(differenceAmount)
                    .add(empSocInfo.getServiceCost()).add(empSocInfo.getLateFees()).stripTrailingZeros().toPlainString());
            empSocInfo.setData(data);
        }
        return resultPage;
    }

    @Override
    public void saveSocOverviewListUserHead(List<CompoundHeadVO> saveHead, TokenUser tokenUser) {
        String socOverviewHeadKey = CacheKeyKit.getSocOverviewHeadKey(tokenUser.getSiteId(), tokenUser.getUserId());
        cache.set(socOverviewHeadKey, saveHead);
    }

    @Override
    public List<CompoundHeadVO> socOverviewListHead(TokenUser tokenUser) {
        String socOverviewHeadKey = CacheKeyKit.getSocOverviewHeadKey(tokenUser.getSiteId(), tokenUser.getUserId());
        List<CompoundHeadVO> currentUserHead = cache.get(socOverviewHeadKey);
        List<EmpSocItemDO> empSocItemList = empSocItemService.selectBySite(tokenUser);
        List<String> itemNameList = empSocItemList.stream()
                .map(EmpSocItemDO::getItemName).distinct().collect(Collectors.toList());
        List<HeaderFieldsTemplateDO> itemHeaderList = adminProviderService
                .selectByCodeAndGroup("socOverview", "子项信息");
        if (CollectionUtils.isEmpty(currentUserHead)) {
            List<CompoundHeadVO> result = new ArrayList<>();
            CompoundHeadVO basic = new CompoundHeadVO();
            // 基础信息
            basic.setName("基础信息");
            addBasicList(basic);
            result.add(basic);
            // 子项信息
            if (!CollectionUtils.isEmpty(itemNameList)) {
                for (String itemName : itemNameList) {
                    CompoundHeadVO itemHead = new CompoundHeadVO();
                    itemHead.setName(itemName);
                    addItemList(itemHead, itemHeaderList);
                    result.add(itemHead);
                }
            }
            CompoundHeadVO other = new CompoundHeadVO();
            other.setName("其他费用");
            addOtherList(other, tokenUser);
            result.add(other);
            CompoundHeadVO total = new CompoundHeadVO();
            // 合计
            total.setName("缴费合计");
            addTotalList(total);
            result.add(total);
            return result;
        } else {
            // 第一级分组的所有名称
            List<String> groupName = currentUserHead.stream()
                    .map(CompoundHeadVO::getName).collect(Collectors.toList());
            Map<String, CompoundHeadVO> headMap = currentUserHead.stream()
                    .collect(Collectors.toMap(CompoundHeadVO::getName, v -> v));
            if (!CollectionUtils.isEmpty(itemNameList)) {
                for (String itemName : itemNameList) {
                    if (!groupName.contains(itemName)) {
                        CompoundHeadVO itemHead = new CompoundHeadVO();
                        itemHead.setName(itemName);
                        addItemList(itemHead, itemHeaderList);
                        currentUserHead.add(currentUserHead.size() - 2, itemHead);
                    }
                }
            }
            CompoundHeadVO otherCompound = headMap.get("其他费用");
            if (ObjectUtils.isEmpty(otherCompound)) {
                CompoundHeadVO other = new CompoundHeadVO();
                other.setName("其他费用");
                addOtherList(other, tokenUser);
                currentUserHead.add(other);
            } else {
                List<SocDifferenceDO> socDifferenceList = this.selectAndDistinctSocDifference(tokenUser);
                List<CompoundHeadVO> childList = otherCompound.getChildList();
                // 当前用户已经保存下来的 其他费用的表头名称
                List<String> childNameList = childList.stream()
                        .map(CompoundHeadVO::getName).collect(Collectors.toList());
                for (SocDifferenceDO socDifference : socDifferenceList) {
                    if (!childNameList.contains(socDifference.getDifferenceName() + "(企业)")) {
                        CompoundHeadVO compoundHead = new CompoundHeadVO();
                        compoundHead.setName(socDifference.getDifferenceName() + "(企业)");
                        compoundHead.setCode(socDifference.getDifferenceName() + "(企业)");
                        compoundHead.setSelected(false);
                        childList.add(compoundHead);
                    }
                    if (!childNameList.contains(socDifference.getDifferenceName() + "(个人)")) {
                        CompoundHeadVO compoundHead = new CompoundHeadVO();
                        compoundHead.setName(socDifference.getDifferenceName() + "(个人)");
                        compoundHead.setCode(socDifference.getDifferenceName() + "(个人)");
                        compoundHead.setSelected(false);
                        childList.add(compoundHead);
                    }
                }
            }
            return currentUserHead;
        }
    }

    @Override
    public String exportSocOverviewList(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        List<CompoundHeadVO> exportHead = query.getExportHead();
        query.setFill(true);
        List<List<String>> headList = new ArrayList<>();
        List<List<String>> codeHeadList = new ArrayList<>();
        for (CompoundHeadVO compoundHead : exportHead) {
            List<CompoundHeadVO> childList = compoundHead.getChildList();
            for (CompoundHeadVO childHead : childList) {
                if (!ObjectUtils.isEmpty(childHead.getSelected()) && childHead.getSelected()) {
                    List<String> head = new ArrayList<>();
                    head.add(compoundHead.getName());
                    head.add(childHead.getName());
                    headList.add(head);
                    List<String> codeHead = new ArrayList<>();
                    codeHead.add(compoundHead.getName());
                    codeHead.add(childHead.getCode());
                    codeHeadList.add(codeHead);
                }
            }
        }
        List<EmpSocInfoListVO> empSocInfoList = socOverviewList(query, tokenUser);
        List<List<String>> dataList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(empSocInfoList)) {
            List<String> empSocInfoId = empSocInfoList.stream()
                    .map(EmpSocInfoListVO::getId).collect(Collectors.toList());
            // 查询出他们的子项
            List<EmpSocItemDO> empSocItemList = empSocItemService
                    .selectByEmpSocIdList(empSocInfoId, tokenUser.getSiteId());
            Map<String, List<EmpSocItemDO>> groupItem = empSocItemList
                    .stream().collect(Collectors.groupingBy(EmpSocItemDO::getEmpSocId));
            List<SocDifferenceDO> socDifferenceList = socDifferenceService
                    .selectBySocInfoIdList(empSocInfoId, tokenUser.getSiteId());
            //
            Map<String, List<SocDifferenceDO>> groupSocDifference = socDifferenceList.stream()
                    .collect(Collectors.groupingBy(SocDifferenceDO::getSocInfoId));
            for (EmpSocInfoListVO empSocInfo : empSocInfoList) {
                List<EmpSocItemDO> infoItem = groupItem.get(empSocInfo.getId());
                List<SocDifferenceDO> differenceList = groupSocDifference.get(empSocInfo.getId());
                List<String> oneData = new ArrayList<>();
                for (List<String> head : codeHeadList) {
                    String headTotal = head.get(0);
                    // 如果是基础信息直接用反射拿
                    if ("基础信息".equals(headTotal)) {
                        Field field;
                        try {
                            field = empSocInfo.getClass().getDeclaredField(head.get(1));
                        } catch (NoSuchFieldException e) {
                            throw new ParamException("导出失败");
                        }
                        field.setAccessible(true);
                        try {
                            Object value = field.get(empSocInfo);
                            if (ObjectUtils.isEmpty(value)) {
                                oneData.add("");
                            } else {
                                oneData.add(value.toString());
                            }
                        } catch (IllegalAccessException e) {
                            throw new ParamException("导出失败");
                        }
                    } else if ("缴费合计".equals(headTotal)) {
                        oneData.add(ExportSocOverview.totalConversion(empSocInfo, differenceList, head.get(1)));
                    } else if ("其他费用".equals(headTotal)) {
                        oneData.add(ExportSocOverview.otherConversion(empSocInfo, differenceList, head.get(1)));
                    } else {
                        oneData.add(ExportSocOverview.itemConversion(headTotal, infoItem, head.get(1)));
                    }
                }
                dataList.add(oneData);
            }
        }
        return ExcelKit.generateExcel("社保总览", headList, "社保总览", dataList, null, null);
    }

    private List<EmpSocInfoListVO> socOverviewList(SocPlanDispatchUserQuery query, TokenUser tokenUser) {
        String[] yearAndMonth = query.getDate().split("-");
        String year = yearAndMonth[0];
        String month = yearAndMonth[1];
        UserCompanyVO userCompany = childCompanyService.selectByUserId(tokenUser.getUserId(), tokenUser.getSiteId());
        Map<String, List<String>> stringListMap = childCompanyService
                .filterCustomerDetailCompanyIds(query.getType(), userCompany, tokenUser.getSiteId());
        List<String> companyIdList = stringListMap.get("permissionGroupAndCompanyIds");
        // 如果是刚创建的租户初始一个用工单位还未创建
        if (CollectionUtils.isEmpty(companyIdList)) {
            return new ArrayList<>();
        }
        List<EmpSocMonthDO> empSocMonthList = empSocMonthService
                .selectByYearAndMonth(companyIdList, year, month, tokenUser.getSiteId());
        List<String> monthIdList = empSocMonthList.stream().map(EmpSocMonthDO::getId).collect(Collectors.toList());
        // 查询当前登录用户的接单数据
        List<EmpSocInfoListVO> dispatchList = new ArrayList<>();
        if ("site".equals(query.getType().getType())) {
            dispatchList = selectTaskSocInfoBuCurrentUser(query, year, month, tokenUser);
        }
        // 查询当前登录用户所有权限下的参保数据
        query.setCompanyIdList(companyIdList);
        query.setMonthIdList(monthIdList);
        List<EmpSocInfoListVO> empSocInfoList;
        if (CollectionUtils.isEmpty(companyIdList) || CollectionUtils.isEmpty(monthIdList)) {
            empSocInfoList = new ArrayList<>();
        } else {
            empSocInfoList = empSocInfoService.getInfoByMonthCompanyList(query, tokenUser);
        }
        // 过滤重复数据
        if (!CollectionUtils.isEmpty(dispatchList)) {
            List<String> infoIdList = empSocInfoList.stream().map(EmpSocInfoListVO::getId).collect(Collectors.toList());
            dispatchList = dispatchList.stream()
                    .filter(dispatch -> !infoIdList.contains(dispatch.getId()))
                    .collect(Collectors.toList());

            empSocInfoList.addAll(dispatchList);
        }
        if (!ObjectUtils.isEmpty(query.getFill()) && query.getFill()) {
            for (EmpSocInfoListVO empSocInfo : empSocInfoList) {
                fillListData(empSocInfo);
            }
        }
        return empSocInfoList;
    }

    private void fillListData(EmpSocInfoListVO empSocInfo) {
        if (ObjectUtils.isEmpty(empSocInfo.getEmpSocStatus())) {
            empSocInfo.setEmpSocStatusStr("未参保");
        } else {
            empSocInfo.setEmpSocStatusStr(EmpSocStatus.find(empSocInfo.getEmpSocStatus()).getDesc());
        }
        if (ObjectUtils.isEmpty(empSocInfo.getEmpMeStatus())) {
            empSocInfo.setEmpMeStatusStr("未参保");
        } else {
            empSocInfo.setEmpMeStatusStr(EmpSocStatus.find(empSocInfo.getEmpMeStatus()).getDesc());
        }
        if (ObjectUtils.isEmpty(empSocInfo.getEmpPfStatus())) {
            empSocInfo.setEmpPfStatusStr("未参保");
        } else {
            empSocInfo.setEmpPfStatusStr(EmpSocStatus.find(empSocInfo.getEmpPfStatus()).getDesc());
        }
        // 户口类型
        if (!ObjectUtils.isEmpty(empSocInfo.getRegType())) {
            empSocInfo.setRegType(RegTypeEnum.find(Integer.parseInt(empSocInfo.getRegType())).getDesc());
        }
        // 缴费类型
        if (!ObjectUtils.isEmpty(empSocInfo.getPayCostType())) {
            empSocInfo.setPayCostTypeStr(SocPayCostType.find(empSocInfo.getPayCostType()).getDesc());
        }
        // 滞纳金
        BigDecimal socialSecurityFine = ObjectUtils.isEmpty(empSocInfo.getSocialSecurityFine()) ?
                new BigDecimal("0") : empSocInfo.getSocialSecurityFine();
        BigDecimal accumulationFundFine = ObjectUtils.isEmpty(empSocInfo.getAccumulationFundFine()) ?
                new BigDecimal("0") : empSocInfo.getAccumulationFundFine();
        empSocInfo.setLateFees(socialSecurityFine.add(accumulationFundFine));
        empSocInfo.setSocDate(empSocInfo.getYear() + "-" + empSocInfo.getMonth());
    }

    /**
     * 基础信息
     */
    private void addBasicList(CompoundHeadVO basic) {
        List<CompoundHeadVO> childList = new ArrayList<>();
        List<HeaderFieldsTemplateDO> basicList = adminProviderService
                .selectByCodeAndGroup("socOverview", "基础信息");
        for (HeaderFieldsTemplateDO basicHead : basicList) {
            CompoundHeadVO child = new CompoundHeadVO();
            child.setName(basicHead.getName());
            child.setCode(basicHead.getCode());
            child.setSelected(basicHead.getIsSee());
            childList.add(child);
        }
        basic.setChildList(childList);
    }

    /**
     * 子项信息
     */
    private void addItemList(CompoundHeadVO item, List<HeaderFieldsTemplateDO> itemHeaderList) {
        List<CompoundHeadVO> childList = new ArrayList<>();
        for (HeaderFieldsTemplateDO headerField : itemHeaderList) {
            CompoundHeadVO compoundHead = new CompoundHeadVO();
            compoundHead.setName(item.getName() + headerField.getName());
            compoundHead.setCode(item.getName() + headerField.getCode());
            compoundHead.setSelected(true);
            childList.add(compoundHead);
        }
        item.setChildList(childList);
    }

    /**
     * 缴费合计
     */
    private void addTotalList(CompoundHeadVO total) {
        List<CompoundHeadVO> childList = new ArrayList<>();
        List<HeaderFieldsTemplateDO> totalHeaderList = adminProviderService
                .selectByCodeAndGroup("socOverview", "缴费合计");
        for (HeaderFieldsTemplateDO headerFields : totalHeaderList) {
            CompoundHeadVO compoundHead = new CompoundHeadVO();
            compoundHead.setName(headerFields.getName());
            compoundHead.setCode(headerFields.getName());
            compoundHead.setSelected("社保公积金总合计".equals(headerFields.getName())
                    || "应收总合计".equals(headerFields.getName()));
            childList.add(compoundHead);
        }
        total.setChildList(childList);
    }

    /**
     * 其他费用
     */
    private void addOtherList(CompoundHeadVO other, TokenUser tokenUser) {
        List<CompoundHeadVO> childList = new ArrayList<>();
        List<HeaderFieldsTemplateDO> totalHeaderList = adminProviderService
                .selectByCodeAndGroup("socOverview", "其他费用");
        for (HeaderFieldsTemplateDO headerFields : totalHeaderList) {
            CompoundHeadVO compoundHead = new CompoundHeadVO();
            compoundHead.setName(headerFields.getName());
            compoundHead.setCode(headerFields.getCode());
            compoundHead.setSelected("服务费".equals(headerFields.getName()));
            childList.add(compoundHead);
        }
        List<SocDifferenceDO> socDifferenceList = this.selectAndDistinctSocDifference(tokenUser);
        if (!CollectionUtils.isEmpty(socDifferenceList)) {
            for (SocDifferenceDO socDifference : socDifferenceList) {
                // 公司
                CompoundHeadVO compoundHeadC = new CompoundHeadVO();
                compoundHeadC.setName(socDifference.getDifferenceName() + "(企业)");
                compoundHeadC.setCode(socDifference.getDifferenceName() + "(企业)");
                compoundHeadC.setSelected(false);
                // 个人
                CompoundHeadVO compoundHeadP = new CompoundHeadVO();
                compoundHeadP.setName(socDifference.getDifferenceName() + "(个人)");
                compoundHeadP.setCode(socDifference.getDifferenceName() + "(个人)");
                compoundHeadP.setSelected(false);
                childList.add(compoundHeadC);
                childList.add(compoundHeadP);
            }
        }
        other.setChildList(childList);
    }

    /**
     * 查询租户下所有的差额费用并且按照名称去重
     */
    private List<SocDifferenceDO> selectAndDistinctSocDifference(TokenUser tokenUser) {
        List<SocDifferenceDO> socDifferenceList = socDifferenceService.selectBySite(tokenUser);
        if (CollectionUtils.isEmpty(socDifferenceList)) {
            return new ArrayList<>();
        }
        socDifferenceList = socDifferenceList.stream()
                .collect(Collectors.collectingAndThen
                        (Collectors.toCollection(() ->
                                        new TreeSet<>(Comparator.comparing(SocDifferenceDO::getDifferenceName))),
                                ArrayList::new
                        )
                );
        return socDifferenceList;
    }

    /**
     * 当前登录人员的接单的对应月份的参保记录
     */
    private List<EmpSocInfoListVO> selectTaskSocInfoBuCurrentUser(SocPlanDispatchUserQuery query,
                                                                  String year, String month, TokenUser tokenUser) {
        Example example = new Example(SocPlanDispatchUserDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("userId", tokenUser.getUserId());
        List<SocPlanDispatchUserDO> planDispatchList = socPlanDispatchUserDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(planDispatchList)) {
            return new ArrayList<>();
        }
        List<String> dispatchEmpIdList = planDispatchList.stream()
                .map(SocPlanDispatchUserDO::getEmpId).collect(Collectors.toList());
        List<String> dispatchCompanyIdList = planDispatchList.stream()
                .map(SocPlanDispatchUserDO::getCompanyId).collect(Collectors.toList());
        List<EmpSocMonthDO> empSocMonthList = empSocMonthService
                .selectByYearAndMonth(dispatchCompanyIdList, year, month, tokenUser.getSiteId());
        List<String> monthIdList = empSocMonthList.stream().map(EmpSocMonthDO::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(monthIdList)) {
            return new ArrayList<>();
        }
        query.setTaskMonthIdList(monthIdList);
        query.setEmpIdList(dispatchEmpIdList);
        return empSocInfoService.getNormalInfoByMonthEmpList(query, tokenUser);
    }

    /**
     * 根据查询参数，构建example
     *
     * @param socPlanDispatchUserQuery 查询参数
     * @param siteId                   所属站点id
     * @return example
     */
    private Example buildExample(SocPlanDispatchUserQuery socPlanDispatchUserQuery, String siteId) {
        Example example = new Example(SocPlanDispatchUserDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        // 排序
        ExampleKit.setExampleOrder(example, socPlanDispatchUserQuery.getOrders());
        return example;
    }
}




